package edu.hawaii.duedates;

//import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
//import java.util.Locale;

import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;
import org.apache.commons.cli.ParseException;

/**
 * DueDates demonstrates simple use of httpunit to retrieve and parse a web page. DueDates when
 * invoked through the command line will retrieve information from the library.
 * 
 * @author John Ancheta
 *         Daniel Arakaki
 *         Mari-Lee Flestado
 * 
 * @version 1.1, October 14, 2008
 */
public class DueDates {

  /**
   * Attempts to login to UH Manoa Library system.
   * 
   * @param id The UH user ID.
   * @param lastName The UH user's last name.
   * @return The WebConversation instance after successful login.
   * @throws Exception If login was not successful with these credentials.
   */
  private static WebConversation loginToUhmLibrary(final String id, final String lastName)
      throws Exception {
    String url = "http://uhmanoa.lib.hawaii.edu/cgi-bin/Pwebrecon.cgi?DB=local&PAGE=pbLogon";
    // UH Library website has bogus JavaScript code.
    HttpUnitOptions.setExceptionsThrownOnScriptError(false);
    // create the conversation object which will maintain state for us
    WebConversation conversation = new WebConversation();
    WebRequest request = new GetMethodWebRequest(url);
    WebResponse response = conversation.getResponse(request);
    WebForm form = response.getFormWithName("logonpage");
    if (id != null && id.length() == 9 && id.charAt(4) == '-') {
      form.setParameter("BC", id.substring(0, 4) + id.substring(5));
    }
    else {
      form.setParameter("BC", id);
    }
    form.setParameter("LN", lastName);
    form.submit();
    response = conversation.getCurrentPage();
    if (response.getText().contains("Sorry, Login unsuccessful")) {
      throw new Exception("Error while logging in to UH Library");
    }
    return conversation;
  }
  
  /**
   * Attempts to login to the Hawaii State Library System.
   * @param barcode The hawaii library id barcode.
   * @param pin The password (last four digits of your phone number).
   * @return The WebConversation after logging in. 
   * @throws Exception If errors occur while logging in. 
   */
  private WebConversation loginToHawaiiStateLibrary(String barcode, String pin) throws Exception {
    try {
      String url = "http://www.librarieshawaii.org/";
      // Website has bogus JavaScript code.
      HttpUnitOptions.setExceptionsThrownOnScriptError(false);
      // create the conversation object which will maintain state for us
      WebConversation conversation = new WebConversation();
      WebRequest request = new GetMethodWebRequest(url);
      WebResponse response = conversation.getResponse(request);
      WebLink link = response.getLinkWith("My Account");
      link.click();
      response = conversation.getCurrentPage();
      WebForm form = response.getForms()[0];
      form.setParameter("sec1", barcode);
      form.setParameter("sec2", pin);
      form.submit();
      return conversation;
    }
    catch (Exception e) {
      throw new Exception ("Error while logging in to Hawaii State Library", e);
    }
  }

  /**
   * The sort information method takes in the book due dates and places the books in chronological
   * order.
   * 
   * @param bookList An arrayList that holds the book information the Date and book title.
   * @return bookInformation A String of the due date's information.
   */
  public static void sortInformation(List<Pair> bookList) {

    /*
     * The system should now support a -sort parameter that takes either library or duedate as its
     * value:
     * 
     * 
     * -sort [library | duedate]
     * 
     * 
     * If the user specifies -sort library, then the resulting table is sorted in alphabetical order
     * by library (if there are multiple books per library, the order in which the books are
     * presented is unspecified.)
     * 
     * 
     * If the user specifies -sort duedate, then the resulting table is sorted in order by
     * increasing due date. In other words, the first book appearing in the list is the book that
     * will be due soonest. The last book appearing in the list is the book that will be due
     * furthest in the future.
     * 
     * 
     * If the -sort parameter is not provided, then the default behavior is -sort library.
     * 
     * 
     * 
     * If the argument to -sort is not library or duedate, the system should report an error.
     */
    String bookInformation = "";
    Collections.sort(bookList);
    for (Pair pair : bookList) {
      bookInformation = pair.getDueDate().toString() + " " + pair.getBookTitle();
    }
  }

  /**
   * Given a logged in user to the UH Library site, provides info about their library books. Should
   * a user have books checked out a formatted list will be presented. If no books are borrowed then
   * a message will be displayed.
   * 
   * @param id The UH user ID.
   * @param lastName The UH user's last name.
   * @param bookList An arraylist of due dates and book titles.
   * @return A String containing information about their books.
   * @throws Exception If problems occur parsing the site pages.
   */
  public String getUhmInfo(String id, String lastName, List<Pair> bookList) throws Exception {
    String dateFormat = "MM-dd-yy";
    SimpleDateFormat formattedDate = new SimpleDateFormat(dateFormat, Locale.US);
    
    try {
      WebConversation conversation = loginToUhmLibrary(id, lastName);
      WebResponse response = conversation.getCurrentPage();
      WebForm form = response.getForms()[0];
      String uhSiteNoItemString = "You have no items checked out.";
      if (uhSiteNoItemString.equals(form.getText())) {
        return "No books checked out";
      }
      else {
        WebTable table = response.getTableStartingWith("Status");
      
        // if the user did not borrow anything from the library
        if (table == null) {
          return "No books checked out";
        }

        for (int i = 1; i <= table.getRowCount() - 1; i++) {
          // add array list
          // String recordDueDate = table.getCellAsText(i, 3);
          String recordDueDate = table.getCellAsText(i, table.getColumnCount() - 1);
          
          if (recordDueDate.length() >= 8) {
            recordDueDate = recordDueDate.substring(recordDueDate.length() - 8);
          }
          String recordBookInfo = table.getCellAsText(i, 1);
          
          Date aDate = formattedDate.parse(recordDueDate);
          bookList.add(new Pair(aDate, recordBookInfo));
        }
        DueDates.sortInformation(bookList);
        return null;
      }
    }
    catch (Exception e) {
      throw new Exception("Unable to get UH Book info:\n  " + e.getMessage(), e);
    }
  }
  
  /**
   * Gets info from the Hawaii State Library site.
   * 
   * @param hiStateId The barcode number from the library card.
   * @param hiStatePassword The password (normally the last four digits of your phone number).
   * @param bookList An arraylist of due dates and book titles.
   * @return A string providing information about checked out books. 
   * @throws Exception If problems occur getting the information. 
   */
  public String getHawaiiStateInfo(String hiStateId, String hiStatePassword,
                        List<Pair> bookList) throws Exception {
    String dateFormat = "MM-dd-yy";
    SimpleDateFormat formattedDate = new SimpleDateFormat(dateFormat, Locale.US); 
    try {
      WebConversation conversation = this.loginToHawaiiStateLibrary(hiStateId, hiStatePassword);
      WebResponse response = conversation.getCurrentPage();
      WebLink link = response.getLinkWith("Items Out");
      link.click();
      response = conversation.getCurrentPage();
      WebTable table = response.getTableStartingWith("Title");
      if (table == null) {
        return "No books checked out";
      }
      int rowCount = table.getRowCount();
      for (int i = 1; i < rowCount; i++) {
          String title = table.getCellAsText(i, 0);
          String duedate = table.getCellAsText(i, 2);
          Date aDate = formattedDate.parse(duedate);
          bookList.add(new Pair(aDate, title));
      }
      return null;
    }
    catch (Exception e) {
      throw new Exception("Error getting Hawaii State Library info", e);
    }
  }
  /**
   * Formats the output for UHM library and HS library.
   * 
   * @param bookList List of borrowed books or other items.
   * @return prints out the formatted output.
   */
  
  public String formatInformation(List<Pair> bookList) {
    Date dueDate;
    String bookTitle = "";
    String formatter = " \t%1$-20.15s | %2$.65s\n";
    System.out.printf(formatter, "Due Date", "Book Info\n");
    int charRow = 65;
    int titleRow = 0;
    for (Pair pair : bookList ) {
      dueDate = pair.getDueDate();
      bookTitle = pair.getBookTitle();
      String result = String.format(formatter, dueDate, bookTitle);
      titleRow = bookTitle.length() / charRow;
      if (bookTitle.length() > 50) {
        if (bookTitle.length() % charRow != 0) {
          titleRow++;
        }
        for (int i = 1; i < titleRow; i++) {
          result = result.concat(String.format(formatter,"", bookTitle.substring(charRow * i)));
        }
        return result; 
      }
      else {
        return String.format(formatter, dueDate, bookTitle);
      }
    }
    return null;
  }

  /**
   * Get only the book list for items that are due in ndaysTillDue or less.
   * 
   * @param ndaysTillDue The number of days till the item is due.
   * @param bookList The original bookList to check.
   * 
   * @return A bookList for only items that are due in ndaysTillDue or less.
   * 
   * @throws Exception For bookList with date format other than MM/dd/yy. 
   * 
   */
  public List<Pair> getWithinBookList(int ndaysTillDue, List<Pair> bookList) throws Exception {
    if (ndaysTillDue <= 0) {
      return bookList;
    }   
    Calendar fromTimeRange = Calendar.getInstance();
    //DateFormat formatter = new SimpleDateFormat("MM-dd-yy", Locale.US);

    List<Pair> withinBookList = new ArrayList<Pair>();
    for (Pair pair : bookList) {
      Date dueDate = pair.getDueDate();
      String bookInfo = pair.getBookTitle();
      //Date date = formatter.parse(dueDate);
      if (fromTimeRange.after(dueDate)) { //past due
        withinBookList.add(new Pair(dueDate, bookInfo));
      }
      else {
        long nmillisecondsTillDue = 86400000L * ndaysTillDue;
        long epochDueDate = dueDate.getTime() - nmillisecondsTillDue;
        long epochFromTimeRange = fromTimeRange.getTime().getTime();
        if (epochDueDate < epochFromTimeRange) {
          withinBookList.add(new Pair(dueDate, bookInfo));
        }
      }
    }
    return withinBookList;
  }

  /**
   * The getSiteInfo method gets the information from the command line. The method needs an argument
   * to verify which site it taking information from.
   * 
   * @param commandLineArgs Holds the command line arguments for DueDates. 
   * @return A String of the user's information from the getUhmInfo method.
   * @throws Exception An exception is thrown when an error occurs while retrieving library
   *         information. 
   */
  public static String getSiteInfo(CommandLineArgs commandLineArgs) throws Exception {
    DueDates dueDates = new DueDates();
    List<Pair> bookList = new ArrayList<Pair>();
    
    if (commandLineArgs.hasUhmOption()) {
      String id = commandLineArgs.getUhmId();
      String lastName = commandLineArgs.getUhmLastName();
      dueDates.getUhmInfo(id, lastName, bookList);
    }

    if (commandLineArgs.hasHslOption()) {
      String barcode = commandLineArgs.getHslId();
      String pin = commandLineArgs.getHslLastFourDigitsForPhoneNumber();
      dueDates.getHawaiiStateInfo(barcode, pin, bookList);
    }
    
    int ndaysTillDue = commandLineArgs.getWithinValue();
    List<Pair> withinBookList = dueDates.getWithinBookList(ndaysTillDue, bookList);
    sortInformation(withinBookList);
    for (Pair pair : withinBookList) {
      System.out.println(pair.getDueDate().toString());
      System.out.println(pair.getBookTitle());
    }
    return null;
    //return dueDates.formatInformation(bookList);
  }

  /**
   * This method assures the proper site is chosen from the command line.
   * 
   * @param option This is an option.
   * @return true if the option equals "-uhm".
   */
  public boolean isUhmOption(String option) {
    return "-uhm".equals(option);
  }

  /**
   * This method assures the proper site is chosen from the command line.
   * 
   * @param option This is an option.
   * @return true if the option equals "-uhm".
   */
  public boolean isHslOption(String option) {
    return "-hsl".equals(option);
  }
  
  /**
   * The sort option.
   * 
   * @param option A String, a command line option.
   * @return true if the option equals "-sort".
   */
  public boolean isSortOption(String option) {
    return "-sort".equals(option);
  }

  /**
   * The main method handles the command line arguments and prints a stack trace when invoked.
   * 
   * @param args Command lines for DueDates.
   */
  public static void main(String[] args) {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    try {
      commandLineArgs.parse(args);
      String siteInfo = DueDates.getSiteInfo(commandLineArgs);
      System.out.println(siteInfo);
    }
    catch (ParseException e1) {
      System.out.println(e1.getMessage());
      commandLineArgs.printHelp();
    }
    catch (Exception e) {
      if (commandLineArgs.hasVerboseOption()) {
        e.printStackTrace();
      }
      else {
        System.out.println(e.getMessage());
      }
    }   
  }
}
